using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Threading;

using InfFront.UICore;

namespace InfFront.InfoViews.Base
{
    /// <summary>
    /// View-side IInfoSourceSet wrapper
    /// </summary>
    public class RootInfoViewSource : InfoViewSource
    {
        #region Private Variables
        #endregion

        #region Construction/Initialization
        public RootInfoViewSource(IInfoSource source, IVisualSettingsAccessor rootSettings)
            : base(source, rootSettings.OpenChildSettings(source.GetName()))
        {
            PlatformCallbacks = new DummyPlatformCallbacks();
        }
        #endregion

        protected internal override RootInfoViewSource RootParent
        {
            get { return this; }
        }

        protected override List<string> InternalPath
        {
            get { return new List<string>(); }
        }

        public InfoViewSource FindByPath(string[] path)
        {
            if (path == null)
                return null;
            InfoViewSource curNode = this;
            for (int i = 0; i < path.Length; ++i)
            {
                InfoViewSource nextNode = null;
                foreach (var src in curNode.NestedSources)
                {
                    if (src.Name == path[i])
                    {
                        nextNode = src;
                        break;
                    }
                }
                curNode = nextNode;
                if (curNode == null)
                    break;
            }
            return curNode;
        }

        public IInfoViewPlatformCallbacks PlatformCallbacks { get; set; }

        internal System.IO.Stream ExtractIImage(IImage src)
        {
            if (src == null)
                return null;
            Debug.Assert (src.GetUid() != string.Empty, "Image caching is not supported yet");

            var result = src.GetData();
            return result;
        }

        #region Async Command Execution

        private void ExecAsyncCall(AsyncCallMethod method, bool waitForFinish, IExecutionControl exec)
        {
            if (!waitForFinish)
            {
                ThreadPool.QueueUserWorkItem(DoExecuteAsyncCallMethod, method);
                return;
            }

            using (var bWorker = new BackgroundWorker())
            {
                bWorker.DoWork += new DoWorkEventHandler(bWorker_DoWork);
                bWorker.RunWorkerAsync(method);
                PlatformCallbacks.DisplayBackgroundWork(bWorker, exec);
            }
        }

        public void ExecAsyncCall(AsyncCallMethod method, bool waitForFinish)
        {
            ExecAsyncCall(method, waitForFinish, null);
        }

        public void ExecAsyncCall(IExecutionControl exec, bool waitForFinish)
        {
            AsyncCallMethod del = delegate() { exec.Execute(); };
            ExecAsyncCall(del, waitForFinish, exec);
        }

        private void DoExecuteAsyncCallMethod(object methodObject)
        {
            var method = (AsyncCallMethod)methodObject;
            try
            {
                method();
            }
            catch (Exception ex)
            {
                PlatformCallbacks.HandleAsyncCallException(ex);
            }
        }

        private void bWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            DoExecuteAsyncCallMethod(e.Argument);
        }

        public void ExecInMainThread(AsyncCallMethod method, bool waitForFinish)
        {
            PlatformCallbacks.ExecInMainThread(method, waitForFinish);
        }

        #endregion Async Command Execution
    }

    public delegate void AsyncCallMethod();

    public interface IInfoViewPlatformCallbacks
    {
        void DisplayBackgroundWork(BackgroundWorker worker, IExecutionControl exec);

        void ExecInMainThread(AsyncCallMethod method, bool waitForFinish);

        void HandleAsyncCallException(Exception ex);
    }

    internal class DummyPlatformCallbacks : IInfoViewPlatformCallbacks
    {
        #region IInfoViewPlatformCallbacks Members

        public void DisplayBackgroundWork(BackgroundWorker worker, IExecutionControl exec)
        {
        }

        public void ExecInMainThread(AsyncCallMethod method, bool waitForTheEnd)
        {
            method();
        }

        public void HandleAsyncCallException(Exception ex)
        {
            throw ex;
        }

        #endregion
    }
}
